﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.ServiceProcess;
using System.IO;
using System.Linq;
using PSE.Framework.Configuration;
using PSE.ProcessManager.Entity;
using System.Collections;

namespace PSE.ProcessManager.ServiceManagerApplication
{
    /// <summary>
    /// Main Form of the Hoster Manager.
    /// </summary>
    public partial class ServiceManagerForm : Form
    {
        #region Constants

        // Constants containing the index of the images of the servers.
        private const int ServerImage = 0;
        private const int SelectedServerImage = 1;
        private const int ServerStoppedImage = 2;
        private const int SelectedServerStoppedImage = 3;
        private const int InstanceImage = 4;
        private const int InstanceSelectedImage = 5;
        private const int ProductServerImage = 6;

        // Constants containing the columns of the services list view.
        private const int ServicesColumnName = 0;

        // The separator to show the selected files from the Add Assembly Form
        private const string FileSeparator = ",";

        // Message showed when the assembly doesn´t have any WCF service.
        private const string NoServiceAssemblyMessage = "<This assembly doesn't have any service running.>";

        #endregion

        #region Private Variables

        // List containing the servers added by the user.
        private List<string> _servers;

        // The splitter position of the server panel before the user collapses it.
        private int _lastSplitterPosition = 0;

        // Last clicked Server Node.
        string _lastClickedServerNode = String.Empty;

        // Last clicked Product Node.
        string _lastClickedProductNode = String.Empty;

        // Last clicked Instance Node.
        Instance _lastClickedInstanceNode = null;

        private TreeNode _contextMenuTreeNode = null;

        private int sortColumn = -1;

        #endregion

        #region Constructor

        /// <summary>
        /// Constructor  
        /// </summary>
        public ServiceManagerForm()
        {
            InitializeComponent();
            this.menuSystemTray.ImageList = imageListServers;
        }

        #endregion

        #region Form Event Handlers

        private void HosterManagerForm_Load(object sender, EventArgs e)
        {
            // Don't show the Servers Collapse Button.
            splitContainerCollapseServers.Panel2Collapsed = true;

            // Refresh the servers packages.
            // Called also to refresh the green and red lights from servers.
            this.RefreshServers();
        }


        private void HosterManagerForm_Resize(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.Hide();
            }
        }

        private void HosterManagerForm_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyData == Keys.F5)
            {
                this.RefreshServers();
            }
        }

        #endregion

        #region "Actions" Menu Handlers

        private void menuAction_DropDownOpening(object sender, EventArgs e)
        {
            // Se todos servidores estiverem iniciados, desabilita Start
            if (_servers.All(s => this.GetServerState(s)))
                menuActionStartServers.Enabled = false;
            else
                menuActionStartServers.Enabled = true;

            // Se todos servidores estiverem parados, desabilita Stop
            if (_servers.All(s => !this.GetServerState(s)))
                menuActionStopServers.Enabled = false;
            else
                menuActionStopServers.Enabled = true;
        }

        /// <summary>
        /// Menu item clicked: Action -> Refresh Servers
        /// Refresh all the servers.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void menuActionRefreshServers_Click(object sender, EventArgs e)
        {
            this.RefreshServers();
        }

        /// <summary>
        /// Menu item clicked: Action -> Add Server...
        /// Add a new server to be monitored by the Service Hoster Manager.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void menuActionAddServer_Click(object sender, EventArgs e)
        {
            this.AddServer();
        }

        private void menuActionStartServers_Click(object sender, EventArgs e)
        {
            this.StartServers();
        }

        private void menuActionStopServers_Click(object sender, EventArgs e)
        {
            this.StopServers();
        }

        /// <summary>
        /// Menu item clicked: Action -> WindowsService -> Stop
        /// Stop the WCF Services Hoster windows service from localhost.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void menuActionExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        #endregion

        #region "Help" Menu Handlers

        private void menuHelpAbout_Click(object sender, EventArgs e)
        {
            using (AboutForm form = new AboutForm())
            {
                form.ShowDialog(this);
            }
        }

        #endregion

        #region "System Tray" Menu Handlers

        private void menuSystemTray_Opening(object sender, CancelEventArgs e)
        {
            // Se todos servidores estiverem iniciados, desabilita Start
            if (_servers.All(s => this.GetServerState(s)))
                menuSystemTrayStartServers.Enabled = false;
            else
                menuSystemTrayStartServers.Enabled = true;

            // Se todos servidores estiverem parados, desabilita Stop
            if (_servers.All(s => !this.GetServerState(s)))
                menuSystemTrayStopServers.Enabled = false;
            else
                menuSystemTrayStopServers.Enabled = true;
        }

        private void menuSystemTrayAddServer_Click(object sender, EventArgs e)
        {
            this.Restore();
            this.AddServer();
        }

        private void menuSystemTrayStartServers_Click(object sender, EventArgs e)
        {
            this.StartServers();
        }

        private void menuSystemTrayStopServers_Click(object sender, EventArgs e)
        {
            this.StopServers();
        }

        private void menuSystemTrayExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void systemTrayIcon_DoubleClick(object sender, EventArgs e)
        {
            this.Restore();
        }

        private void menuSystemTrayServer_Opening(object sender, CancelEventArgs e)
        {
            // Verify the icon to see if server is active.
            if (((ContextMenuStrip)sender).OwnerItem.ImageIndex == ServerImage)
            {
                // Disable the start service menu item.
                menuSystemTrayServerStart.Enabled = false;
                menuSystemTrayServerStop.Enabled = true;
            }
            else
            {
                // Disable the stop service menu item
                menuSystemTrayServerStart.Enabled = true;
                menuSystemTrayServerStop.Enabled = false;
            }

            menuSystemTrayServerStart.Tag = ((ContextMenuStrip)sender).OwnerItem.Text;
            menuSystemTrayServerStop.Tag = ((ContextMenuStrip)sender).OwnerItem.Text;
        }

        private void menuSystemTrayServerStart_Click(object sender, EventArgs e)
        {
            string serverName = (string)((ToolStripDropDownItem)sender).Tag;

            this.StartServer(serverName);
        }

        private void menuSystemTrayServerStop_Click(object sender, EventArgs e)
        {
            string serverName = (string)((ToolStripDropDownItem)sender).Tag;

            this.StopServer(serverName, true);
        }

        #endregion

        #region "Servers" Context Menu Handlers

        private void menuServers_Opening(object sender, CancelEventArgs e)
        {
            this.RefreshSelectedTreeNode();

            if (!string.IsNullOrEmpty(_lastClickedServerNode))
            {
                // If the node is the localhost server don't allow remove it.
                if (_lastClickedServerNode == "localhost")
                {
                    removeServerMenuItem.Enabled = false;
                }
                else
                {
                    removeServerMenuItem.Enabled = true;
                }

                // Verify the icon to see if server is active.
                if (this.trvServers.SelectedNode != null &&
                    this.trvServers.SelectedNode.ImageIndex == ServerImage)
                {
                    // Disable the start service menu item.
                    startServerMenuItem.Enabled = false;
                    stopServerMenuItem.Enabled = true;
                }
                else
                {
                    // Disable the stop service menu item
                    startServerMenuItem.Enabled = true;
                    stopServerMenuItem.Enabled = false;
                }
            }
            else
            {
                e.Cancel = true;
            }
        }

        private void addServerMenuItem_Click(object sender, EventArgs e)
        {
            using (AddServerForm form = new AddServerForm())
            {
                form.ShowDialog(this);
                this.RefreshServers();
            }
        }

        private void removeServerMenuItem_Click(object sender, EventArgs e)
        {
            this.RemoveServer();
        }

        private void refreshServerMenuItem_Click(object sender, EventArgs e)
        {
            this.RefreshServer(_lastClickedServerNode, true);
        }

        private void startServerMenuItem_Click(object sender, EventArgs e)
        {
            this.StartServer(_lastClickedServerNode);
        }

        private void stopServerMenuItem_Click(object sender, EventArgs e)
        {
            this.StopServer(_lastClickedServerNode, true);
        }

        #endregion

        #region "Products" Context Menu Handlers

        private void menuProducts_Opening(object sender, CancelEventArgs e)
        {
            this.RefreshSelectedTreeNode();

            if (!string.IsNullOrEmpty(_lastClickedProductNode))
            {
                TreeNode node = trvServers.Nodes.Find("PROD_" + _lastClickedServerNode + "_" + _lastClickedProductNode, true)[0];
                IEnumerable<TreeNode> instances = node.Nodes.Cast<TreeNode>();

                bool allStarted = instances.All(inst => ((Instance)inst.Tag).ProcessId > -1);
                bool allStopped = instances.All(inst => ((Instance)inst.Tag).ProcessId == -1);

                startProductMenuItem.Enabled = !allStarted;
                stopProductMenuItem.Enabled = !allStopped;
                restartProductMenuItem.Enabled = !allStopped;
            }
            else
            {
                e.Cancel = true;
            }
        }

        private void startProductMenuItem_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;

            try
            {
                using (StartWindowsServiceForm form = new StartWindowsServiceForm(_lastClickedServerNode, _lastClickedProductNode, true))
                {
                    form.ShowDialog(this);
                }

                this.RefreshServer(_lastClickedServerNode, false);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }

        private void stopProductMenuItem_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;

            try
            {
                using (StartWindowsServiceForm form = new StartWindowsServiceForm(_lastClickedServerNode, _lastClickedProductNode, false))
                {
                    form.ShowDialog(this);
                }

                this.RefreshServer(_lastClickedServerNode, false);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }

        private void restartProductMenuItem_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;

            try
            {
                using (StartWindowsServiceForm form = new StartWindowsServiceForm(_lastClickedServerNode, _lastClickedProductNode, false))
                {
                    form.ShowDialog(this);
                }

                using (StartWindowsServiceForm form = new StartWindowsServiceForm(_lastClickedServerNode, _lastClickedProductNode, true))
                {
                    form.ShowDialog(this);
                }

                this.RefreshServer(_lastClickedServerNode, false);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }

        #endregion

        #region "Instances" Context Menu Handlers

        private void menuInstances_Opening(object sender, CancelEventArgs e)
        {
            this.RefreshSelectedTreeNode();

            if (_lastClickedInstanceNode != null)
            {
                if (_lastClickedInstanceNode.ProcessId == -1)
                {
                    startInstanceMenuItem.Enabled = true;
                    stopInstanceMenuItem.Enabled = false;
                    restartInstanceMenuItem.Enabled = false;
                }
                else
                {
                    startInstanceMenuItem.Enabled = false;
                    stopInstanceMenuItem.Enabled = true;
                    restartInstanceMenuItem.Enabled = true;
                }
            }
            else
            {
                e.Cancel = true;
            }
        }

        private void startInstanceMenuItem_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;

            try
            {
                using (StartWindowsServiceForm form = new StartWindowsServiceForm(_lastClickedServerNode, _lastClickedInstanceNode.ProductName, _lastClickedInstanceNode.InstanceName, true))
                {
                    form.ShowDialog(this);
                }

                this.RefreshServer(_lastClickedServerNode, false);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }

        private void stopInstanceMenuItem_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;

            try
            {
                Business.StopInstance(_lastClickedServerNode, _lastClickedInstanceNode.ProductName, _lastClickedInstanceNode.InstanceName);

                this.RefreshServer(_lastClickedServerNode, false);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }

        private void restartInstanceMenuItem_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;

            try
            {
                Business.StopInstance(_lastClickedServerNode, _lastClickedInstanceNode.ProductName, _lastClickedInstanceNode.InstanceName);

                using (StartWindowsServiceForm form = new StartWindowsServiceForm(_lastClickedServerNode, _lastClickedInstanceNode.ProductName, _lastClickedInstanceNode.InstanceName, true))
                {
                    form.ShowDialog(this);
                }

                this.RefreshServer(_lastClickedServerNode, false);
            }
            catch (Exception ex)
            {
                this.ShowErrorMessage(ex.Message);
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }

        #endregion

        #region "Process" Context Menu Handlers

        private void startProcessMenuItem_Click(object sender, EventArgs e)
        {
            IEnumerable<ProcessEntity> processes = lvwProcesses.SelectedItems.Cast<ListViewItem>().Select<ListViewItem, ProcessEntity>(l => (ProcessEntity)l.Tag);

            if (processes.Any(p => p.InitializationType != PSE.ProcessManager.Entity.Enums.StartUpType.Automatic))
            {
                this.ShowWarningMessage("It's not possible to start processes with 'Manual' initialization type from this interface, please select only 'Automatic' processes.");
                return;
            }

            this.Cursor = Cursors.WaitCursor;

            try
            {
                foreach (ProcessEntity process in processes)
                {
                    if (process.ProcessId == -1)
                        Business.StartProcess(_lastClickedServerNode, _lastClickedProductNode, _lastClickedInstanceNode.InstanceName, process.Id.Value);
                }

                this.RefreshProcessesList();
            }
            catch (Exception ex)
            {
                this.ShowErrorMessage(ex.Message);
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }

        private void stopProcessMenuItem_Click(object sender, EventArgs e)
        {
            IEnumerable<ProcessEntity> processes = lvwProcesses.SelectedItems.Cast<ListViewItem>().Select<ListViewItem, ProcessEntity>(l => (ProcessEntity)l.Tag);

            this.Cursor = Cursors.WaitCursor;

            try
            {
                foreach (ProcessEntity process in processes)
                {
                    if (process.ProcessId > -1)
                        Business.StopProcess(_lastClickedServerNode, _lastClickedProductNode, _lastClickedInstanceNode.InstanceName, process.Id.Value);
                }

                this.RefreshProcessesList();
            }
            catch (Exception ex)
            {
                this.ShowErrorMessage(ex.Message);
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }

        #endregion

        #region Expand and Collapse Panel Methods

        private void picHide_MouseEnter(object sender, EventArgs e)
        {
            picHide.Image = imageListPin.Images[1];
        }

        private void picHide_MouseLeave(object sender, EventArgs e)
        {
            picHide.Image = imageListPin.Images[0];
        }

        private void picHide_Click_1(object sender, EventArgs e)
        {
            splitContainerCollapseServers.Panel1Collapsed = true;
            splitContainerCollapseServers.Panel2Collapsed = false;

            _lastSplitterPosition = splitContainer1.SplitterDistance;

            splitContainer1.FixedPanel = FixedPanel.Panel1;
            splitContainer1.IsSplitterFixed = true;
            splitContainer1.SplitterDistance = 25;
        }

        private void picServers_Click(object sender, EventArgs e)
        {
            splitContainerCollapseServers.Panel1Collapsed = false;
            splitContainerCollapseServers.Panel2Collapsed = true;

            splitContainer1.FixedPanel = FixedPanel.None;
            splitContainer1.IsSplitterFixed = false;
            splitContainer1.SplitterDistance = _lastSplitterPosition;
        }

        #endregion

        #region Servers TreeView Event Handlers

        private void trvServers_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (e.Node == null)
            {
                _lastClickedServerNode = null;
                _lastClickedProductNode = null;
                _lastClickedInstanceNode = null;

                lvwProcesses.Items.Clear();
                lvwProcessDetail.Items.Clear();
            }
            else if (e.Node.Name.StartsWith("SRV"))
            {
                _lastClickedServerNode = e.Node.Text;
                _lastClickedProductNode = null;
                _lastClickedInstanceNode = null;

                lvwProcesses.Items.Clear();
                lvwProcessDetail.Items.Clear();
            }
            else if (e.Node.Name.StartsWith("PROD"))
            {
                _lastClickedServerNode = e.Node.Parent.Text;
                _lastClickedProductNode = (string)e.Node.Tag;
                _lastClickedInstanceNode = null;

                lvwProcesses.Items.Clear();
                lvwProcessDetail.Items.Clear();
            }
            else if (e.Node.Name.StartsWith("INST"))
            {
                _lastClickedServerNode = e.Node.Parent.Parent.Text;
                _lastClickedProductNode = (string)e.Node.Parent.Tag;
                _lastClickedInstanceNode = (Instance)e.Node.Tag;
                this.RefreshProcessesList();
            }

            this.ChangeSelectedItensMessage();
        }

        private void trvServers_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                System.Drawing.Point p = new System.Drawing.Point(e.X, e.Y);
                _contextMenuTreeNode = trvServers.GetNodeAt(p);
            }
        }

        private void trvServers_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyData == Keys.Delete)
            {
                if (!string.IsNullOrEmpty(_lastClickedServerNode))
                {
                    if (_lastClickedInstanceNode != null)
                    {
                        //this.RemovePackage();
                    }
                    else
                    {
                        this.RemoveServer();
                    }
                }
            }
        }

        private void RefreshSelectedTreeNode()
        {
            if (_contextMenuTreeNode != null)
            {
                trvServers.SelectedNode = _contextMenuTreeNode;
                _contextMenuTreeNode = null;
            }
        }

        #endregion

        #region Processes ListView Event Handlers

        private void lvwProcesses_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                bool allStarted = lvwProcesses.SelectedItems.Cast<ListViewItem>().All(p => ((ProcessEntity)p.Tag).ProcessId > -1);
                bool allStopped = lvwProcesses.SelectedItems.Cast<ListViewItem>().All(p => ((ProcessEntity)p.Tag).ProcessId == -1);

                menuProcesses.Items["startProcessMenuItem"].Enabled = !allStarted;
                menuProcesses.Items["stopProcessMenuItem"].Enabled = !allStopped;

                menuProcesses.Show(lvwProcesses, e.Location);
            }
        }

        private void lvwProcesses_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.RefreshProcessDetail();
        }

        private void lvwProcesses_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            // Determine whether the column is the same as the last column clicked.
            if (e.Column != sortColumn)
            {
                // Set the sort column to the new column.
                sortColumn = e.Column;
                // Set the sort order to ascending by default.
                lvwProcesses.Sorting = SortOrder.Ascending;
            }
            else
            {
                // Determine what the last sort order was and change it.
                if (lvwProcesses.Sorting == SortOrder.Ascending)
                    lvwProcesses.Sorting = SortOrder.Descending;
                else
                    lvwProcesses.Sorting = SortOrder.Ascending;
            }

            // Call the sort method to manually sort.
            lvwProcesses.Sort();
            // Set the ListViewItemSorter property to a new ListViewItemComparer
            // object.
            lvwProcesses.ListViewItemSorter = new ListViewItemComparer(e.Column, lvwProcesses.Sorting);
        }

        #endregion

        #region Private UI Methods

        private void Restore()
        {
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.Show();
                this.WindowState = FormWindowState.Normal;
            }
            else
            {
                this.Activate();
            }
        }

        private void RefreshServers()
        {
            // Clear the assemblies and service lists.
            lvwProcesses.Items.Clear();
            lvwProcessDetail.Items.Clear();

            // Get the servers from the configuration file and fill the Server TreeView.
            try
            {
                _servers = Business.GetServersFromConfigurationFile();

                this.BuildServerTree(_servers);

                // Refresh System Tray Servers
                this.BuildServersMenu();
            }
            catch (Exception ex)
            {
                this.ShowErrorMessage(ex.Message);
            }

            // Refresh all the servers to show if they are alive or not.
            foreach (string server in _servers)
            {
                this.RefreshServer(server, false);
            }
        }

        private void RefreshServer(string serverName, bool showMessageError)
        {
            this.Cursor = Cursors.WaitCursor;

            try
            {
                int index = trvServers.Nodes.IndexOfKey("SRV_" + serverName);
                trvServers.Nodes[index].Nodes.Clear();

                lvwProcesses.Items.Clear();
                lvwProcessDetail.Items.Clear();

                List<string> products = Business.ListProducts(serverName);

                foreach (string product in products)
                {
                    this.AddProductNode(serverName, product);

                    List<Instance> instances = Business.ListInstances(serverName, product);

                    foreach (Instance instance in instances)
                    {
                        this.AddInstanceNode(serverName, instance);
                    }
                }

                trvServers.Nodes[index].ExpandAll();
            }
            catch (Exception ex)
            {
                this.Cursor = Cursors.Default;
                if (showMessageError)
                    this.ShowErrorMessage(ex.Message);
                return;
            }

            this.ChangeServerIcon(serverName, Business.IsServerStarted(serverName));

            this.Cursor = Cursors.Default;
        }

        //private void LockedServerIcon(string serverName)
        //{
        //    int index = trvServers.Nodes.IndexOfKey("SRV_" + serverName);

        //    trvServers.Nodes[index].ImageIndex = LockedServerImage;
        //    trvServers.Nodes[index].SelectedImageIndex = LockedServerImage;

        //    this.menuSystemTray.Items["menuSystemTrayServer_" + serverName].ImageIndex = LockedServerImage;
        //}

        private void ChangeServerIcon(string serverName, bool alive)
        {
            int index = trvServers.Nodes.IndexOfKey("SRV_" + serverName);
            if (alive)
            {
                trvServers.Nodes[index].ImageIndex = ServerImage;
                trvServers.Nodes[index].SelectedImageIndex = SelectedServerImage;

                this.menuSystemTray.Items["menuSystemTrayServer_" + serverName].ImageIndex = ServerImage;
            }
            else
            {
                trvServers.Nodes[index].ImageIndex = ServerStoppedImage;
                trvServers.Nodes[index].SelectedImageIndex = SelectedServerStoppedImage;

                this.menuSystemTray.Items["menuSystemTrayServer_" + serverName].ImageIndex = ServerStoppedImage;
            }
        }

        private void ClearLists()
        {
            lvwProcesses.Items.Clear();
            lvwProcessDetail.Items.Clear();
        }

        private void BuildServerTree(IList<string> servers)
        {
            trvServers.BeginUpdate();
            trvServers.Nodes.Clear();
            foreach (string server in servers)
            {
                AddServerNode(server);
            }
            trvServers.SelectedNode = trvServers.Nodes[0];
            trvServers.SelectedNode.ExpandAll();
            trvServers.EndUpdate();
        }

        private void AddServerNode(string serverName)
        {
            TreeNode node = trvServers.Nodes.Add("SRV_" + serverName, serverName);
            node.ImageIndex = ServerStoppedImage;
            node.SelectedImageIndex = SelectedServerStoppedImage;
            node.ContextMenuStrip = menuServers;
        }

        private void AddProductNode(string serverName, string productName)
        {
            int index = trvServers.Nodes.IndexOfKey("PROD_" + serverName + "_" + productName);
            if (index == -1)
            {
                int serverNodeIndex = trvServers.Nodes.IndexOfKey("SRV_" + serverName);
                TreeNode node = new TreeNode();
                node.Name = "PROD_" + serverName + "_" + productName;

                node.Tag = productName;
                node.Text = SystemComponents.GetSystem(productName).Description;

                node.ImageIndex = ProductServerImage;
                node.SelectedImageIndex = ProductServerImage;
                node.ContextMenuStrip = menuProducts;
                trvServers.Nodes[serverNodeIndex].Nodes.Add(node);
            }
        }

        private void AddInstanceNode(Instance instance)
        {
            this.AddInstanceNode(_lastClickedServerNode, instance);
        }

        private void AddInstanceNode(string serverName, Instance instance)
        {
            int index = trvServers.Nodes.IndexOfKey("INST_" + serverName + "_" + instance.ProductName + "_" + instance.InstanceName);
            if (index == -1)
            {
                TreeNode productNode = trvServers.Nodes.Find("PROD_" + serverName + "_" + instance.ProductName, true)[0];

                TreeNode node = new TreeNode();
                node.Name = "INST_" + serverName + "_" + instance.ProductName + "_" + instance.InstanceName;

                node.Tag = instance;
                node.Text = string.Format("{0} (PID: {1})", instance.InstanceName, instance.ProcessId);

                node.ImageIndex = InstanceImage;
                node.SelectedImageIndex = InstanceSelectedImage;
                node.ContextMenuStrip = menuInstances;

                productNode.Nodes.Add(node);
            }
        }

        private void RefreshProcessesList()
        {
            lvwProcesses.Items.Clear();
            lvwProcessDetail.Items.Clear();

            if (_lastClickedInstanceNode != null && _lastClickedInstanceNode.ProcessId > -1)
            {
                List<ProcessEntity> processes = null;

                try
                {
                    processes = Business.ListProcesses(_lastClickedServerNode, _lastClickedInstanceNode.ProductName, _lastClickedInstanceNode.InstanceName);
                }
                catch (Exception ex)
                {
                    this.RefreshServers();
                    this.ShowErrorMessage(ex.Message);
                    return;
                }

                foreach (ProcessEntity process in processes)
                {
                    ListViewItem item = new ListViewItem();
                    item.Tag = process;
                    item.Text = process.Id.ToString();
                    item.ImageIndex = process.ProcessId == -1 ? 0 : 1;

                    item.SubItems.Add(process.Name);
                    item.SubItems.Add(process.ProcessId.ToString());
                    item.SubItems.Add(process.InitializationType.ToString());

                    lvwProcesses.Items.Add(item);
                }
            }
        }

        private void ChangeSelectedItensMessage()
        {
            lblSelectedItems.Text = string.Format("Server: [{0}]  -  Product: [{1}]  -  Instance: [{2}]",
                _lastClickedServerNode,
                !string.IsNullOrEmpty(_lastClickedProductNode) ? SystemComponents.GetSystem(_lastClickedProductNode).Description : string.Empty,
                _lastClickedInstanceNode != null ? _lastClickedInstanceNode.InstanceName : string.Empty);
        }

        private void RefreshProcessDetail()
        {
            lvwProcessDetail.Items.Clear();

            if (lvwProcesses.SelectedItems.Count > 0)
            {
                ProcessEntity process = (ProcessEntity)lvwProcesses.SelectedItems[0].Tag;

                ListViewItem item = new ListViewItem();
                item.Text = "Process Id:";
                item.SubItems.Add(process.Id.ToString());
                lvwProcessDetail.Items.Add(item);

                item = new ListViewItem();
                item.Text = "Process Name:";
                item.SubItems.Add(process.Name);
                lvwProcessDetail.Items.Add(item);

                item = new ListViewItem();
                item.Text = "Description:";
                item.SubItems.Add(process.Description);
                lvwProcessDetail.Items.Add(item);

                item = new ListViewItem();
                item.Text = "Assembly:";
                item.SubItems.Add(process.Assembly);
                lvwProcessDetail.Items.Add(item);

                item = new ListViewItem();
                item.Text = "Class:";
                item.SubItems.Add(process.Class);
                lvwProcessDetail.Items.Add(item);

                item = new ListViewItem();
                item.Text = "InitializationType:";
                item.SubItems.Add(process.InitializationType.ToString());
                lvwProcessDetail.Items.Add(item);

                item = new ListViewItem();
                item.Text = "FailureRecovery:";
                item.SubItems.Add(process.FailureRecovery.ToString());
                lvwProcessDetail.Items.Add(item);

                item = new ListViewItem();
                item.Text = "InstanceContext:";
                item.SubItems.Add(process.InstanceContext.ToString());
                lvwProcessDetail.Items.Add(item);

                item = new ListViewItem();
                item.Text = "InteligenceModule:";
                item.SubItems.Add(Business.GetInteligenceModule(_lastClickedServerNode, process.InteligenceModuleId).Name);
                lvwProcessDetail.Items.Add(item);

                item = new ListViewItem();
                item.Text = "PID:";
                item.SubItems.Add(process.ProcessId.ToString());
                lvwProcessDetail.Items.Add(item);
            }
        }

        private void AddServer()
        {
            using (AddServerForm form = new AddServerForm())
            {
                form.ShowDialog(this);
                this.RefreshServers();
            }
        }

        private void RemoveServer()
        {
            string message = string.Format("Are you sure you want to remove server '{0}'?", _lastClickedServerNode);

            if (MessageBox.Show(message, "Remove Server", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
            {
                this.Cursor = Cursors.WaitCursor;

                Business.RemoveServer(_lastClickedServerNode);

                this.RefreshServers();

                this.Cursor = Cursors.Default;
            }
        }

        private void StartServers()
        {
            foreach (string serverName in _servers)
            {
                if (!this.GetServerState(serverName))
                {
                    this.StartServer(serverName);
                }
            }
        }

        private void StopServers()
        {
            if (DialogResult.Yes == MessageBox.Show("Are you sure you want to stop all servers?", "WCF Services Hoster Manager", MessageBoxButtons.YesNo, MessageBoxIcon.Question))
            {
                foreach (string serverName in _servers)
                {
                    if (this.GetServerState(serverName))
                    {
                        this.StopServer(serverName, false);
                    }
                }
            }
        }

        private void StartServer(string serverName)
        {
            using (StartWindowsServiceForm form = new StartWindowsServiceForm(serverName, true))
            {
                form.ShowDialog(this);
            }

            this.RefreshServer(serverName, false);
        }

        private void StopServer(string serverName, bool confirm)
        {
            if (!confirm || DialogResult.Yes == MessageBox.Show(string.Format("Are you sure you want to stop server '{0}'?", serverName), "WCF Services Hoster Manager", MessageBoxButtons.YesNo, MessageBoxIcon.Question))
            {
                using (StartWindowsServiceForm form = new StartWindowsServiceForm(serverName, false))
                {
                    form.ShowDialog(this);
                }

                this.RefreshServer(serverName, false);
            }
        }

        private bool GetServerState(string serverName)
        {
            return trvServers.Nodes["SRV_" + serverName].ImageIndex == ServerImage;
        }

        private void BuildServersMenu()
        {
            // Refresh System Tray Servers
            foreach (string serverName in _servers)
            {
                if (!this.menuSystemTray.Items.ContainsKey("menuSystemTrayServer_" + serverName))
                {
                    this.menuSystemTray.Items.Insert(this.menuSystemTray.Items.IndexOf(menuSystemTrayBottomServersSeparator),
                                                     this.CreateMenuSystemTrayServer(serverName));
                }
            }

            for (int i = this.menuSystemTray.Items.Count - 1; i >= 0; i--)
            {
                if (this.menuSystemTray.Items[i].Name.StartsWith("menuSystemTrayServer_") &&
                    !_servers.Contains(this.menuSystemTray.Items[i].Text))
                {
                    this.menuSystemTray.Items[i].Dispose();
                }
            }
        }

        private ToolStripMenuItem CreateMenuSystemTrayServer(string serverName)
        {
            return new ToolStripMenuItem()
            {
                Name = "menuSystemTrayServer_" + serverName,
                Text = serverName,
                DropDown = menuSystemTrayServer
            };
        }

        #endregion

        #region Show Exception Messages

        private void ShowCommunicationErrorMessage(string serverName)
        {
            this.Cursor = Cursors.Default;
            MessageBox.Show(String.Format("Could not communicate with server {0}", serverName), "Communication Error", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void ShowWarningMessage(string message)
        {
            MessageBox.Show(message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }

        private void ShowErrorMessage(string message)
        {
            MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        #endregion

        #region Exception Handlers

        private void CommunicationExceptionHandler(string serverName)
        {
            // Clear the packages from the server node
            int index = trvServers.Nodes.IndexOfKey("SRV_" + serverName);
            TreeNode node = trvServers.Nodes[index];
            node.Nodes.Clear();
            // Clear the assembly and service list views.
            this.ClearLists();
            // Change the icon of the server showing that the server is down.
            this.ChangeServerIcon(serverName, false);

            _lastClickedProductNode = null;
            _lastClickedInstanceNode = null;

            this.ChangeSelectedItensMessage();
        }

        #endregion

        class ListViewItemComparer : IComparer
        {
            private int col;
            private SortOrder order;

            public ListViewItemComparer()
            {
                col = 0;
                order = SortOrder.Ascending;
            }

            public ListViewItemComparer(int column, SortOrder order)
            {
                col = column;
                this.order = order;
            }

            public int Compare(object x, object y)
            {
                int returnVal = -1;

                int valX;
                int valY;

                if (int.TryParse(((ListViewItem)x).SubItems[col].Text, out valX) &&
                    int.TryParse(((ListViewItem)y).SubItems[col].Text, out valY))
                {
                    returnVal = valX.CompareTo(valY);
                }
                else
                {
                    returnVal = String.Compare(((ListViewItem)x).SubItems[col].Text, ((ListViewItem)y).SubItems[col].Text);
                }

                // Determine whether the sort order is descending.
                if (order == SortOrder.Descending)
                    // Invert the value returned by String.Compare.
                    returnVal *= -1;

                return returnVal;
            }
        }
    }
}
